import React, {
  useState,
  forwardRef,
  useImperativeHandle,
  useRef,
  useEffect
} from 'react'
import { Form, Tabs, Button, Space, Row, Col, message } from 'antd'
import { CloseOutlined } from '@ant-design/icons'

import {
  MODELS,
  NsNodeCmd,
  useXFlowApp,
  useXflowPrefixCls,
  uuidv4,
  WorkspacePanel,
  XFlowGraphCommands,
  XFlowNodeCommands
} from '@antv/xflow'
import type { NsGraph, IPosition } from '@antv/xflow'
import { PlayBookService } from '@/service'

import {
  BaseFormItems,
  AddVariablesFormItemsNew,
  DynamicFormItems
} from './partials'
import { InputEdit, Table } from '@/components'
import styles from './index.module.less'
import { formatFormConfigs } from './utils/formatFormConfigs'
import { NODE_TYPE } from '@/constants'

export interface IPanelProps {
  position: IPosition
}

interface FormPanelProps {
  setVisible: (visible: boolean) => void
  data?: NsGraph.INodeConfig
  onClose?: () => void
  // openScriptDraw: (data: NsGraph.INodeConfig) => void
}

interface FormPanelRef {
  initDraw: (data: NsGraph.INodeConfig) => void
  close: () => void
}

const { TabPane } = Tabs

const FormPanelContent = forwardRef(
  (props: FormPanelProps, ref: React.Ref<FormPanelRef>) => {
    const { setVisible /* openScriptDraw */ } = props
    const [meta, setMeta] = useState({})
    const app = useXFlowApp()

    useEffect(() => {
      MODELS.GRAPH_META.useValue(modelService).then(meta => {
        setMeta(meta)
      })
    }, [])

    const { commandService, modelService, getNodeById, getGraphData } =
      useXFlowApp()

    const [form] = Form.useForm()
    const [nodeInfo, setNodeInfo] = useState<NsGraph.INodeConfig | {}>({})
    const [formConfigs, setFormConfigs] = useState([])

    const onClose = () => {
      setVisible(false)
    }
    const onSubmit = () => {
      form.validateFields().then(() => {
        const formValue = form.getFieldsValue(true)
        if (nodeInfo.data.nodeType === NODE_TYPE.START) {
          // 更新画布node信息
          getNodeById(nodeInfo.id).then(node => {
            const nodeData = node.data
            commandService.executeCommand<NsNodeCmd.UpdateNode.IArgs>(
              XFlowNodeCommands.UPDATE_NODE.id,
              {
                nodeConfig: {
                  ...nodeData,
                  data: {
                    ...nodeData.data,
                    variables: {
                      value: formValue.variables
                    }
                  }
                }
              }
            )
            message.success('保存成功')
          })
        } else if (nodeInfo.data.nodeType === NODE_TYPE.SWITCH) {
          // 更新画布node信息
          getNodeById(nodeInfo.id).then(node => {
            const nodeData = node.data
            commandService.executeCommand<NsNodeCmd.UpdateNode.IArgs>(
              XFlowNodeCommands.UPDATE_NODE.id,
              {
                nodeConfig: {
                  ...nodeData,
                  data: {
                    ...nodeData.data,
                    input: {
                      form: nodeData.data.input.form,
                      value: formValue.input
                    }
                  }
                }
              }
            )
            message.success('保存成功')
          })
        } else {
          // 全局获取的变量 存值格式 [] -> ''
          const globalVariablesObj = nodeInfo.data.globalVariables.reduce(
            (prev, item) => {
              prev[item] =
                formValue.input[item][formValue.input[item].length - 1]
              return prev
            },
            {}
          )

          const saveInstance = () => {
            return MODELS.GRAPH_META.useValue(modelService).then(({ name }) => {
              if (formValue.instance_id) {
                // 已经创建过了
                return PlayBookService.updateInstance({
                  instance_id: formValue.instance_id,
                  params: { ...formValue.input, ...globalVariablesObj },
                  name: `${name}_${formValue.display}`
                })
              } else {
                // debugger
                return PlayBookService.createInstance({
                  integration_id: formValue.integration_id,
                  command: formValue.name,
                  params: { ...formValue.input, ...globalVariablesObj },
                  name: `${name}_${formValue.display}`
                })
              }
            })
          }
          saveInstance()
            .then(({ instance_id }) => {
              // 更新画布node信息
              getNodeById(nodeInfo.id).then(node => {
                const nodeData = node.data
                commandService.executeCommand<NsNodeCmd.UpdateNode.IArgs>(
                  XFlowNodeCommands.UPDATE_NODE.id,
                  {
                    nodeConfig: {
                      ...nodeData,
                      label: formValue.display,
                      data: {
                        ...nodeData.data,
                        ...formValue,
                        input: {
                          form: nodeData.data.input.form,
                          value: formValue.input
                        },
                        instance_id
                      }
                    }
                  }
                )
                message.success('保存成功')
              })
            })
            .catch(err => {
              message.error(err)
            })
        }
      })
    }
    useImperativeHandle(ref, () => ({
      initDraw: nodeData => {
        setVisible(true)
        form.resetFields()
        const { data } = nodeData
        form.setFieldsValue({
          integration_id: data.integration_id,
          display: data.display,
          name: data.name,
          description: data.description,
          // category: data.category,
          tags: data.tags,
          variables: data?.variables?.value, // 开始节点
          input: data?.input?.value, // 普通节点
          output: data?.output, // 普通节点
          instance_id: data?.instance_id, // 实例的id
          globalVariables: data?.globalVariables
        })

        setNodeInfo(nodeData)
        // 有input再继续，排除开始节点
        if (!data?.input) return
        // 获取开始节点的变量
        const getStartNodeOptions = getNodeById('start').then(node => {
          const startNodeData = node.data
          const startNodeOptions =
            startNodeData.data.variables.value.length > 0
              ? [
                  {
                    label: '开始节点',
                    value: 'start',
                    children: startNodeData.data.variables.value.map(
                      ({ display, name }) => ({
                        label: display,
                        value: name
                      })
                    )
                  }
                ]
              : []
          return [...startNodeOptions]
        })
        const getPrevNodesOptions = (nodeData, nodeIdMap, edgeIdMap) => {
          const getPrevNodeIds = nodeData => {
            let prevNodeIds: string[] = []

            if (!nodeData.incomingEdges) return []
            for (const prevEdges of nodeData.incomingEdges) {
              // 删除向量，与该向量的节点并未同步，还保留该incomingEdges
              if (!edgeIdMap.get(prevEdges.id)) continue
              const prevNodeId = prevEdges.data.data.source
              const prevNode = nodeIdMap.get(prevNodeId)
              const {
                data: { nodeType }
              } = prevNode
              if (nodeType !== 'start' && !prevNodeIds.includes(prevNodeId)) {
                if (nodeType !== 'switch') {
                  prevNodeIds.push(prevNodeId)
                }
                const prevNode = nodeIdMap.get(prevNodeId)
                prevNodeIds = [...prevNodeIds, ...getPrevNodeIds(prevNode)]
              }
            }
            return [...new Set(prevNodeIds)] // 有重复 ，待优化
          }
          const prevNodeIds = getPrevNodeIds(nodeData)
          const prevNodesOptions = prevNodeIds.map(prevNodeId => {
            const nodeData = nodeIdMap.get(prevNodeId)
            return {
              label: nodeData.data.display,
              value: /* nodeData.data.name */ prevNodeId, // 防止标识相同
              children: nodeData.data.output
            }
          })
          return Promise.resolve(prevNodesOptions)
        }
        const getGlobalVariablesOption = nodeData => {
          return getGraphData()
            .then(({ nodes, edges }) => {
              const nodeIdMap = new Map()
              for (const node of nodes) {
                nodeIdMap.set(node.id, node)
              }
              const edgeIdMap = new Map()
              for (const edge of edges) {
                edgeIdMap.set(edge.id, edge)
              }
              return {
                nodeIdMap,
                edgeIdMap
              }
            })
            .then(({ nodeIdMap, edgeIdMap }) => {
              return Promise.all([
                getStartNodeOptions,
                getPrevNodesOptions(nodeData, nodeIdMap, edgeIdMap)
              ]).then(([startNodeOptions, prevNodesOptions]) => {
                return [...startNodeOptions, ...prevNodesOptions]
              })
            })
        }
        getGlobalVariablesOption(nodeData).then(options => {
          for (const globalVariable of data.globalVariables) {
            for (const formItem of data.input.form) {
              if (formItem.field === globalVariable) {
                formItem.options = options
              }
            }
          }
          setFormConfigs(formatFormConfigs(data.input.form))
        })
      },
      close: onClose
    }))

    const renderFormBodyByNodeType = (
      { nodeType, output } = { nodeType: '', output: [] }
    ) => {
      if (nodeType === NODE_TYPE.START) {
        return (
          <AddVariablesFormItemsNew
            disabled={meta.mode === 'check'}
            field="variables"
          />
        )
      } else if (nodeType === NODE_TYPE.SWITCH) {
        return <DynamicFormItems formConfigs={formConfigs} field="input" />
      } else if (nodeType === NODE_TYPE.NORMAL) {
        return (
          <>
            <BaseFormItems />
            <Tabs type="card" className="variable-config-card">
              <TabPane tab="输入配置" key="1">
                <DynamicFormItems formConfigs={formConfigs} field="input" />
              </TabPane>
              <TabPane tab="输出配置" key="2">
                <Table
                  pagination={false}
                  dataSource={output}
                  columns={[
                    {
                      title: '序号',
                      render: (text, record, index) => `${index + 1}`
                    },
                    { title: '输出项', dataIndex: 'label' },
                    { title: '数据标识', dataIndex: 'value' },
                    { title: '数据类型', dataIndex: 'type' }
                  ]}
                />
              </TabPane>
            </Tabs>
          </>
        )
      } else if (nodeType === NODE_TYPE.END) {
        return null
      }
    }
    return (
      <>
        <Form
          autoComplete="off"
          form={form}
          labelCol={{ span: 6 }}
          labelWrap
          disabled={meta.mode === 'check'}
        >
          <Row className="node-config-draw-header">
            <Col span={12}>
              <Form.Item
                name="display"
                rules={[{ required: true, message: '请输入节点名称' }]}
              >
                <InputEdit
                  disabled={
                    [NODE_TYPE.START, NODE_TYPE.END, NODE_TYPE.SWITCH].includes(
                      nodeInfo?.data?.nodeType
                    ) || meta.mode === 'check'
                  }
                />
              </Form.Item>
            </Col>
            <Col span={12} className="node-config-draw-close-icon">
              <CloseOutlined onClick={onClose} />
            </Col>
          </Row>
          <div className="node-config-draw-body">
            {renderFormBodyByNodeType(nodeInfo?.data)}
          </div>
          {/* <Button onClick={() => openScriptDraw(nodeInfo.node_conf.script)}>脚本编辑</Button> */}
          <Row className="node-config-draw-footer">
            <Space>
              <Button onClick={onClose}>取消</Button>
              <Button type="primary" onClick={onSubmit}>
                确定
              </Button>
            </Space>
          </Row>
        </Form>
      </>
    )
  }
)

const JSONFormPanel = (props: IPanelProps, ref: React.Ref<FormPanelRef>) => {
  const prefixClz = useXflowPrefixCls('form-panel')
  const { position = { width: 400, top: 0, bottom: 0, right: 0 } } = props
  const [visible, setVisible] = useState(false)
  const { width = 400, right } = position

  return (
    <WorkspacePanel
      className={`${styles[prefixClz]} ${visible ? styles['active'] : ''}`}
      style={{
        transition: '.3s cubic-bezier(.23,1,.32,1)',
        zIndex: 1000
      }}
      position={{
        ...position,
        right: visible ? right : -width
      }}
    >
      <FormPanelContent setVisible={setVisible} ref={ref} />
    </WorkspacePanel>
  )
}

export default forwardRef(JSONFormPanel)
